<template>
  <div>
    <VxeTableVue
      ref="tableEl"
      module-name="角色"
      :queryFormData="state.formData"
      :column-config="columnConfig"
      data-list-api="/auth/role/page"
      delete-api="/auth/role"
      update-or-add-api="/auth/role"
      add-permi="role-add-role"
      del-permi="role-del-role"
      update-permi="role-update-role"
      :show-action-column="hasPermi(['role-update-role', 'role-del-role', 'role-disable-role', 'role-assign-auth'])"
      :add-data="state.addItemData"
      :dialog-form-rules="rules"
      :actionColumnWidth="250"
      :fnObject="tableMapObj"
      @before-open-dialog="onOpenDialog"
    >
      <!------------------------------------------ 查询区域 ------------------------------------------------------->
      <template #queryItem>
        <el-form-item label="角色名称" prop="keyword" class="mgr30">
          <el-input v-model="state.formData.keyword" placeholder="请输入名称或拼音首字母" clearable />
        </el-form-item>
        <el-form-item label="角色状态" prop="lockFlag" class="mgr30">
          <SelectVue
            v-model="state.formData.lockFlag"
            clearable
            :option-list="[
              { name: '启用', id: '0' },
              { name: '禁用', id: '1' }
            ]"
            style="width: 200px"
          />
        </el-form-item>
      </template>

      <!------------------------------------------ 表格插槽 ------------------------------------------------------->

      <template #lockFlag="{ row }: SlotRole">
        <el-tag :type="row.lockFlag === '0' ? 'success' : 'danger'">{{ row.lockFlag === '0' ? '启用' : '禁用' }}</el-tag>
      </template>

      <template #userList="{ row }: SlotRole">
        <el-link type="primary" @click="handleOpenUserDraw(row)">{{ row.userIds?.length ?? 0 }}</el-link>
      </template>

      <template #topExtra="{ selectedList }">
        <span class="mgl20">已选</span>
        <span class="mgr5 mgl5" style="color: var(--el-color-primary)">{{ selectedList.length }}</span>
        <span>个</span>
      </template>

      <template #extraBtn2="{ row }: SlotRole">
        <el-button v-has-permi="['role-disable-role']" type="primary" :disabled="['服务人员', '服务运维人员'].includes(row.roleName)" link @click="handleStatus(row)">{{
          row.lockFlag === '1' ? '启用' : '禁用'
        }}</el-button>

        <el-button v-has-permi="['role-assign-auth']" type="primary" link @click="handleAssignAuth(row)">权限配置</el-button>
      </template>

      <!------------------------------------------ 修改、新增弹窗插槽 ------------------------------------------------------->

      <template #dialogUpdateOrAdd="{ row }: SlotRole">
        <el-row v-if="state.loadForm" class="flex">
          <el-form-item label="角色编码" prop="roleCode" class="mgr30 flex1">
            <el-input v-model="row.roleCode" disabled />
          </el-form-item>
          <el-form-item label="角色名称" prop="roleName" class="flex1">
            <el-input v-model="row.roleName" placeholder="请输入角色名称" />
          </el-form-item>
        </el-row>
      </template>
    </VxeTableVue>

    <!------------------------------------------ 抽屉 ------------------------------------------------------->

    <DrawerVue ref="drawerUserEl" title="角色与用户维护" :show-footer="false" size="40%" @close="reflesh">
      <div class="bold">{{ state.drawerRoleData.roleName }}</div>
      <div class="flex-row-center-between">
        <div class="flex">
          <div class="title-primary bold">已分配用户</div>
          <div class="mgl20">{{ state.drawerRoleData.userList?.length }}个</div>
        </div>
        <div class="mat10 mgb10">
          <el-button type="primary" @click="handleUserByRole('add')">添加</el-button>
          <el-button type="danger" @click="handleUserByRole('delete')">移除</el-button>
        </div>
      </div>
      <TableVue :column-config="drawerColConfig" :data-list="state.drawerRoleData.userList" :show-table-top="false" :show-action-column="false">
        <template #roleList="{ row }: SlotUser">
          <div>{{ row.roleList?.map(item => item.roleName).join(',') }}</div>
        </template>
      </TableVue>
    </DrawerVue>

    <!------------------------------------------ 添加或者移除用户 ------------------------------------------------------->

    <DrawerVue
      ref="drawerUserHanleEl"
      size="40%"
      title="角色与用户维护"
      :form-data="state.drawerRoleData"
      :loading="state.loading"
      api="/auth/role"
      api-method="put"
      @closed="getUsersByRoleId"
      :before-close="authDrawerBeforeClose"
      @refactor-params="onRefactorParms"
      @submit-success="getUsersByRoleId"
    >
      <div v-loading="state.loading">
        <div class="bold">{{ state.drawerRoleData.roleName }}</div>
        <div class="title-primary bold mgt10 mgb10">{{ state.handleUserType === 'add' ? '添加用户' : '移除用户' }}</div>
        <div class="flex">
          <div class="left flex1 mgr5 container br10 pd10">
            <el-input v-model="state.queryUserKeyword" class="mgb30 search" clearable placeholder="输入用户名或拼音首字母">
              <template #append>
                <el-button :icon="Search" @click="getAllUsers" />
              </template>
            </el-input>

            <el-checkbox-group v-model="state.addCheckedUserIds">
              <el-checkbox style="width: 130px" v-for="item in state.allUsers" :key="item.id" :label="item.name" :value="item.id" @change="onCheckBoxChange($event, item)" />
            </el-checkbox-group>
          </div>

          <div class="right flex1 mgl5 container br10 pd10">
            <div class="mgb50 flex-row-center-between">
              <span>选择用户</span>
              <span>{{ state.addCheckedUserIds.length }}个</span>
            </div>
            <el-tag v-for="id in state.addCheckedUserIds" :key="id" closable type="primary" class="mgr10 mgb10" @close="handleDeleteTag(id)">
              {{ state.addCheckedUsers.find(item => item.id === id)?.name }}
            </el-tag>
          </div>
        </div>
      </div>
    </DrawerVue>

    <DrawerVue
      ref="drawerAssignAuthEl"
      title="权限配置"
      api="/auth/role/menu"
      api-method="put"
      :before-close="authDrawerBeforeClose"
      :form-data="state.authTreeFormData"
      @refactor-params="onRefactorTreeParams"
      @submit-success="tableEl?.query()"
    >
      <div class="bold mgb20">{{ state.authAssignRoleName }}</div>
      <el-tabs v-model="state.activeTab" type="border-card" stretch>
        <el-tab-pane label="菜单权限" name="1">
          <el-tree
            style="height: calc(100vh - 280px); overflow: auto"
            ref="authTreeEl"
            default-expand-all
            :check-strictly="false"
            node-key="id"
            :default-checked-keys="state.defaultCheckedPermission"
            :data="state.authList"
            :props="{ label: 'name', children: 'children' }"
            show-checkbox
          />
        </el-tab-pane>
        <!-- <el-tab-pane label="数据权限" name="2">数据权限</el-tab-pane> -->
      </el-tabs>
    </DrawerVue>
  </div>
</template>

<script setup lang="ts">
  import { ref, reactive, nextTick } from 'vue'
  import { Search } from '@element-plus/icons-vue'
  import type { TreeInstance } from 'element-plus'
  import TableVue, { VxeTableVue, type VxeTableViewInstance, type IPropsFnObject } from '@/components/table'
  import DrawerVue, { type DrawerVueInstance } from '@/components/drawer'
  import { Ui, hasPermi } from '@/utils'
  import SelectVue from '@/components/select'
  import request, { type IPage } from '@/service'
  import { columnConfig, drawerColConfig } from './config'
  import type { IRoleEntity, IUserEntity, SlotRole, SlotUser, HandleUserType, IRoleFormData, IAuthFormData } from './config'
  import type { IMenuEntity } from '../menu/config'
  import { toArrayTree, findTree } from 'xe-utils'

  const tableEl = ref<VxeTableViewInstance>()
  const drawerUserEl = ref<DrawerVueInstance | null>()
  const drawerUserHanleEl = ref<DrawerVueInstance | null>()
  const drawerAssignAuthEl = ref<DrawerVueInstance | null>()
  const authTreeEl = ref<TreeInstance | null>()

  const initAddData = () => {
    return {
      roleName: '',
      roleCode: ''
    }
  }

  const state = reactive({
    loading: false,
    loadForm: true,
    formData: {
      keyword: '',
      lockFlag: ''
    },
    drawerRoleData: {} as IRoleEntity,
    handleUserType: 'add' as HandleUserType,
    queryUserKeyword: '',
    allUsers: [] as IUserEntity[],
    addCheckedUsers: [] as IUserEntity[],
    addCheckedUserIds: [] as string[],
    addItemData: initAddData(),

    authList: [] as IMenuEntity[],
    defaultCheckedPermission: [] as string[],
    activeTab: '1',
    authAssignRoleName: '',
    authTreeFormData: {
      id: '',
      menuIds: []
    },

    validateCloseType: '' as 'user' | 'menu'
  })

  let rawMenuIds: string[] = []
  let rawUserIds: string[] = []

  const rules = {
    roleName: [{ required: true, message: '请输入姓名', trigger: 'blur' }]
  }

  const tableMapObj: IPropsFnObject = {
    disableUpdate(data) {
      const arr = ['服务人员', '服务运维人员']
      return arr.includes(data.roleName)
    },
    disableRowDel(data) {
      const arr = ['服务人员', '服务运维人员']
      return arr.includes(data.roleName)
    }
  }

  /**----------------------------methods----------------------------------------------------------------------- */

  /**
   * 关闭抽屉前校验
   * @param done
   */
  type ValidateFn = (cancel?: boolean) => void
  const authDrawerBeforeClose = (done: ValidateFn) => {
    const rawList = state.validateCloseType === 'menu' ? rawMenuIds : rawUserIds
    const chooseList = state.validateCloseType === 'menu' ? getChooseMenuIds() : state.addCheckedUserIds

    const useTip = () => {
      Ui.useMessageBox({
        text: '本次修改的数据未保存，确定关闭？',
        handleConfirm() {
          done()
        },
        handleCancle() {
          done(true)
        }
      })
    }

    if (chooseList.length !== rawList.length) return useTip()
    for (const id of chooseList) {
      const findId = rawList.find(item => item === id)
      if (!findId) return useTip()
    }
    done()
  }

  /**
   * 提交用户
   * @param data
   */
  const onRefactorParms = (data: IRoleFormData) => {
    data.userIds = state.addCheckedUserIds
  }

  const onOpenDialog = (type: 'add' | 'update', data: IRoleEntity) => {
    if (type === 'add') {
      state.addItemData = initAddData()
      state.loadForm = false
      request.get('/auth/role/code').then(res => {
        if (res.code !== 0) return Ui.useMessage('error', res.msg)
        data.roleCode = res.data
        nextTick(() => (state.loadForm = true))
      })
    }
  }

  /**
   * 打开分配权限抽屉
   * @param row
   */
  const handleAssignAuth = (row: IRoleEntity) => {
    state.defaultCheckedPermission = []
    state.authTreeFormData.id = row.id
    state.authAssignRoleName = row.roleName
    state.validateCloseType = 'menu'
    drawerAssignAuthEl.value?.handleOpen()
    getAllAuth()
  }

  /**
   * 所有权限
   */
  const getAllAuth = () => {
    request.get<IMenuEntity[]>('/auth/menu/tree', { current: 1, size: 9999 }).then(res => {
      if (res.code !== 0) return Ui.useMessage('error', res.msg)
      state.authList = res.data
      getAuthByRoleId()
    })
  }

  /**
   * 获取角色下的权限
   */
  const getAuthByRoleId = () => {
    request.get<IMenuEntity[]>(`/auth/menu/tree/${state.authTreeFormData.id}`).then(res => {
      if (res.code !== 0) return Ui.useMessage('error', res.msg)

      rawMenuIds = res.data.map(item => item.id)

      const transferTree = toArrayTree(res.data)
      const checkedIds = formatTree(state.authList, transferTree)

      state.defaultCheckedPermission = checkedIds
    })
  }

  /**
   *
   * @param tree 所有权限
   * @param selectedTree 分配的全选
   * @param ids 过滤初以来的id
   */
  const formatTree = (tree: IMenuEntity[], selectedTree: IMenuEntity[], ids: string[] = []) => {
    selectedTree.forEach(item => {
      const findItem = findTree(tree, rawItem => rawItem.id === item.id)
      if (!findItem.item.children?.length) findItem.item.children = []
      if (findItem && findItem.item.children.length == item.children?.length) ids.push(item.id)
      if (item.children?.length) formatTree(tree, item.children, ids)
    })

    return ids
  }

  /**
   * 提交分配权限
   * @param params
   */
  const onRefactorTreeParams = (params: IAuthFormData) => {
    params.menuIds = getChooseMenuIds()
  }

  /**
   * 获取选择的菜单权限
   */
  const getChooseMenuIds = () => {
    const keys = authTreeEl.value?.getCheckedKeys() as string[]
    const halfKeys = authTreeEl.value?.getHalfCheckedKeys() as string[]
    const menuIds = [...halfKeys, ...keys]
    return menuIds
  }

  /**
   * 新增或移除用户抽屉
   * @param type
   */
  const handleUserByRole = (type: HandleUserType) => {
    getAllUsers()
    state.handleUserType = type
    state.validateCloseType = 'user'
    drawerUserHanleEl.value?.handleOpen()
  }

  /**
   * 删除标签
   */
  const handleDeleteTag = (id: string) => {
    const index = state.addCheckedUserIds.findIndex(item => item === id)
    state.addCheckedUserIds.splice(index, 1)
  }

  /**
   * 角色下的用户抽屉
   */
  const handleOpenUserDraw = (row: IRoleEntity) => {
    state.drawerRoleData = row
    getUsersByRoleId()
    drawerUserEl.value?.handleOpen()
  }

  const onCheckBoxChange = (checked: boolean, user: IUserEntity) => {
    if (checked) state.addCheckedUsers.push(user)
  }

  /**
   * 获取角色下的用户
   */
  const getUsersByRoleId = () => {
    request.get<IRoleEntity>(`/auth/role/${state.drawerRoleData.id}`).then(res => {
      if (res.code !== 0) return Ui.useMessage('error', res.msg)

      rawUserIds = res.data.userList.map(user => user.id)

      state.drawerRoleData.userList = res.data.userList
      state.addCheckedUserIds = res.data.userList.map(item => item.id)
      state.addCheckedUsers = res.data.userList
    })
  }

  /**
   * 启用 禁用
   * @param row
   */
  const handleStatus = (role: IRoleEntity) => {
    const handleConfirm = () => {
      role.lockFlag = role.lockFlag === '0' ? '1' : '0'
      request.put('/auth/role', role).then(res => {
        if (res.code !== 0) return Ui.useMessage('error', res.msg)
        tableEl.value?.query()
      })
    }

    Ui.useMessageBox({
      handleConfirm,
      text: role.lockFlag === '1' ? '是否确认启用该角色?' : '是否确认禁用该角色?'
    })
  }

  /**
   * 查询所有用户
   */
  const getAllUsers = () => {
    state.loading = true
    request
      .get<IPage<IUserEntity>>('/auth/user/page', { current: 1, size: 9999, keyword: state.queryUserKeyword })
      .then(res => {
        if (res.code !== 0) return Ui.useMessage('error', res.msg)
        state.allUsers = res.data.records
      })
      .finally(() => (state.loading = false))
  }

  const reflesh = () => {
    tableEl.value?.query()
  }

  /**----------------------------lifecycle----------------------------------------------------------------------- */
</script>

<style scoped lang="less">
  .container {
    border: 1px solid var(--el-border-color);
    height: 650px;
    overflow: auto;
    .search {
      position: sticky;
      top: -10px;
      z-index: 999;
    }
  }
</style>
